package com.wdl.modules.myhouse.service.impl.oauth2;

import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wdl.modules.myhouse.common.Code;
import com.wdl.modules.myhouse.common.Constant;
import com.wdl.modules.myhouse.common.Result;
import com.wdl.modules.myhouse.dao.SysUserDao;
import com.wdl.modules.myhouse.dao.oauth2.Oauth2WeiboDao;
import com.wdl.modules.myhouse.dao.security.SecurityDao;
import com.wdl.modules.myhouse.entity.UserEntity;
import com.wdl.modules.myhouse.entity.oauth2.Oauth2WeiboEntity;
import com.wdl.modules.myhouse.entity.sys.SysUserEntity;
import com.wdl.modules.myhouse.entity.sys.SysUserRoleEntity;
import com.wdl.modules.myhouse.security.common.SecurityConstant;
import com.wdl.modules.myhouse.security.dto.oauth2.weibo.WeiBoToken;
import com.wdl.modules.myhouse.security.dto.oauth2.weibo.WeiboUserInfo;
import com.wdl.modules.myhouse.security.entity.UserInfo;
import com.wdl.modules.myhouse.service.SysUserRoleService;
import com.wdl.modules.myhouse.service.SysUserService;
import com.wdl.modules.myhouse.service.UserService;
import com.wdl.modules.myhouse.service.oauth2.Oauth2WeiboService;
import com.wdl.modules.myhouse.utils.util.DateUtil;
import com.wdl.modules.myhouse.utils.util.HttpUtils;
import com.wdl.modules.myhouse.utils.util.JsonUtil;
import com.wdl.modules.myhouse.utils.util.RedisUtil;
import com.wdl.modules.myhouse.vo.UserVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.User;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

/**
 * @author 昏昏的君
 */
@Service
@Slf4j
public class Oauth2WeiboServiceImpl extends ServiceImpl<Oauth2WeiboDao, Oauth2WeiboEntity> implements Oauth2WeiboService {

    @Autowired
    private Oauth2WeiboDao weiboDao;
    @Autowired
    private RestTemplate restTemplate;

    @Value("${oauth2.weibo.key}")
    private String appKey;
    @Value("${oauth2.weibo.secret}")
    private String appSecret;
    @Value("${oauth2.weibo.redirect-url}")
    private String redirectUrl;
    @Value("${oauth2.weibo.baseUrl}")
    private String weiboBaseUrl;


    @Autowired
    private SysUserService sysuserService;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private AuthenticationSuccessHandler successHandler;
    @Autowired
    private SecurityDao securityDao;
    @Autowired
    private SysUserDao sysUserDao;
    @Autowired
    private UserService userService;
    @Autowired
    private SysUserRoleService sysUserRoleService;


    @Autowired
    private RedisUtil redisUtil;


    @Override
    public Boolean updateByWeiboUid(Oauth2WeiboEntity weiboEntity) {
        QueryWrapper<Oauth2WeiboEntity> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(Oauth2WeiboEntity::getUid, weiboEntity.getUid());
        return this.update(weiboEntity,wrapper);
    }

    @Transactional
    @Override
    public Result<UserVo> weiboLoginSuccess(String code, HttpServletRequest req, HttpServletResponse resp) throws IOException {
        log.info("获取code成功,code: {}", code);
        HashMap<String, Object> map = new HashMap<>();
        map.put("client_id", appKey);
        map.put("client_secret", appSecret);
        map.put("grant_type", "authorization_code");
        map.put("redirect_uri", redirectUrl);
        map.put("code", code);
//        ResponseEntity<WeiBoToken> responseEntity = restTemplate.postForEntity(weiboBaseUrl + "/access_token", null, WeiBoToken.class, map);
//        WeiBoToken weiboToken = responseEntity.getBody();
        String tokenJson = HttpUtils.postRequest(weiboBaseUrl + "/access_token", map);
        if (tokenJson.contains("error")) {
            JSONObject err = JsonUtil.stringToJsonObj(tokenJson);
            log.warn("获取token异常: {}", err.get("error_description"));
            return new Result<UserVo>().error(Code.TOKEN_UNLEGAL.getCode(),tokenJson);
        }
        WeiBoToken weiboToken = JsonUtil.string2Obj(tokenJson, WeiBoToken.class);
        // 获取用户身份信息,必须带上token
        WeiboUserInfo weiboUserInfo = getUserInfo(weiboToken);
        //1. 数据库中查找当前用户信息
      return  persistenceUserInfo(req, resp, weiboUserInfo);
    }


    private Result<UserVo> persistenceUserInfo(HttpServletRequest req, HttpServletResponse resp, WeiboUserInfo weiboUserInfo) {
        long weiboUid = weiboUserInfo.getId();
        String username = "WEIBO:" + weiboUid;
        UserInfo sysUserInfo = securityDao.getUserInfoByUsername(username);
        if (sysUserInfo == null) {

            //1. 保存系统用户信息
            SysUserEntity entity = new SysUserEntity();
            entity.setUsername("WEIBO:" + weiboUid);
            entity.setPassword(passwordEncoder.encode(Constant.DEFAULT_PASSWORD));

            sysUserDao.insert(entity);


            // 2. 添加用户角色关联信息
            SysUserRoleEntity userRoleEntity = new SysUserRoleEntity();
            userRoleEntity.setUid(entity.getId());
            userRoleEntity.setRid(1);
            sysUserRoleService.save(userRoleEntity);

            sysUserInfo=securityDao.getUserInfoByUsername("WEIBO:"+weiboUid);
            // 3. 保存微博用户其他信息
            Oauth2WeiboEntity weiboEntity = new Oauth2WeiboEntity();
            BeanUtils.copyProperties(weiboUserInfo, weiboEntity);
            weiboEntity.setUid(String.valueOf(weiboUserInfo.getId()));
            weiboEntity.setUserId(entity.getId());

            //4. 更新或者插入微博登录用户的信息
            Oauth2WeiboEntity weiboUser = this.getOne(new QueryWrapper<Oauth2WeiboEntity>().eq("uid", weiboUserInfo.getId()));
            if (weiboUser != null) {
                this.update(weiboEntity, new QueryWrapper<Oauth2WeiboEntity>().eq("uid", weiboUserInfo.getId()));
            } else {
                this.save(weiboEntity);
            }
            // 5. 维护本站用户信息表
            UserEntity userDescEntity = new UserEntity();
            userDescEntity.setUserId(entity.getId());
            userService.save(userDescEntity);
        } else {
            //todo 完善微博二次登录用户信息操作
            Oauth2WeiboEntity weiboEntity =new Oauth2WeiboEntity();
            BeanUtils.copyProperties(weiboUserInfo, weiboEntity);
            weiboEntity.setUid(String.valueOf(weiboUserInfo.getId()));
            weiboEntity.setUserId(sysUserInfo.getId());
            //根据微博uid更新用户三方信息
            if (!this.updateByWeiboUid(weiboEntity)) {
                log.warn("微博登录: 用户信息更新失败");
            }
        }
        //关联系统用户信息
        UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(sysUserInfo, sysUserInfo.getPassword(), sysUserInfo.getAuthorities());
        return this.successHandler(auth,resp);
    }

    private Result<UserVo> successHandler(Authentication authentication,HttpServletResponse response){

        UserInfo user = (UserInfo) authentication.getPrincipal();
        //返回token
        Result<UserVo> res = new Result<UserVo>().ok();
        //jwt中存入uid
        String token = JWT.create()
                .withClaim(SecurityConstant.TOKEN_FIELD, user.getId())
                .withExpiresAt(DateUtil.datePushBackByDays(new Date(), SecurityConstant.JWT_TIME_OUT))
                .sign(Algorithm.HMAC256(SecurityConstant.TOKEN_SIGN));
        //持久化，redis存入全量用户信息
        user.setToken(token);
        redisUtil.setValue(user.getId().toString(), JsonUtil.obj2String(user), RedisUtil.getTimeOut(1, 3), TimeUnit.HOURS);

        //封装用户vo
        UserVo userVo = new UserVo();
        UserEntity userDesc = userService.getUserByUserId(user.getId());
        BeanUtils.copyProperties(userDesc, userVo);
        userVo.setToken(token);
        userVo.setUserName(user.getUsername());
        userVo.setId(user.getId());

        res.setData(userVo);
        res.setMsg("登录成功");
        return res;
    }

    /**
     * 利用达到的token获取用户信息
     * @param token
     * @return
     */
    private WeiboUserInfo getUserInfo(WeiBoToken token) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("access_token", token.getAccess_token());
        map.put("uid", token.getUid());
        String identity = "https://api.weibo.com/2/users/show.json";
        String userInfoJson = HttpUtils.getRequest(identity, map);
        WeiboUserInfo info = JsonUtil.string2Obj(userInfoJson, WeiboUserInfo.class);
        return info;
    }
}
